/*
	This file is part of Kompex SQLite Wrapper.
	Copyright (c) 2008-2024 Sven Broeske

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.
*/

#ifndef KompexSQLiteStatement_H
#define KompexSQLiteStatement_H

#include <map>
#include <string>

#include "sqlite3.h"

#include "KompexSQLitePrerequisites.h"

namespace Kompex
{	
	class SQLiteDatabase;

	enum ENCODING
	{
		UTF8 = 1,
		UTF16LE = 2,
		UTF16BE = 3,
		UTF16 = 4,
		UTF16_ALIGNED = 8
	};

	//! Execution of SQL statements and result processing.
	class _SQLiteWrapperExport SQLiteStatement
	{
	public:
		//! Constructor.\n
		//! @param db		Database in which the SQL should be performed
		SQLiteStatement(SQLiteDatabase *db);
		//! Destructor.
		virtual ~SQLiteStatement();

		//! Only for SQL statements which have no result (e.g. INSERT, UPDATE, etc).\n
		//! Can be used for transactions; if you want, you can use an own error handling.\n
		//! Please use 1 (true) and 0 (false) as bool values instead of 'true' and 'false' as string.\n
		//! sqlite doesn't know these key words.
		//! @param sqlStatement		SQL statement (UTF-8) 
		inline void SqlStatement(const std::string &sqlStatement) {SqlStatement(sqlStatement.c_str());}
		//! Only for SQL statements which have no result (e.g. INSERT, UPDATE, etc).\n
		//! Can be used for transactions; if you want, you can use an own error handling.\n
		//! Please use 1 (true) and 0 (false) as bool values instead of 'true' and 'false' as string.\n
		//! sqlite doesn't know these key words.
		//! @param sqlStatement		SQL statement (UTF-8) 
		void SqlStatement(const char *sqlStatement);
		//! Only for SQL statements which have no result (e.g. INSERT, UPDATE, etc).\n
		//! Can be used for transactions; if you want, you can use an own error handling.\n
		//! Please use 1 (true) and 0 (false) as bool values instead of 'true' and 'false' as string.\n
		//! sqlite doesn't know these key words.
		//! @param sqlStatement		SQL statement (UTF-16) 
		inline void SqlStatement(const std::wstring &sqlStatement) {SqlStatement(sqlStatement.c_str());}
		//! Only for SQL statements which have no result (e.g. INSERT, UPDATE, etc).\n
		//! Can be used for transactions; if you want, you can use an own error handling.\n
		//! Please use 1 (true) and 0 (false) as bool values instead of 'true' and 'false' as string.\n
		//! sqlite doesn't know these key words.
		//! @param sqlStatement		SQL statement (UTF-16) 
		void SqlStatement(const wchar_t *sqlStatement);

		//! Only for SQL queries/statements which have a result or for prepared statements.\n
		//! e.g. SELECT's or INSERT's which use Bind..() methods!\n
		//! Do not forget to call FreeQuery() when you have finished.
		inline void Sql(const std::string &sql) {Prepare(sql.c_str());}
		//! Only for SQL queries/statements which have a result or for prepared statements.\n
		//! e.g. SELECT's or INSERT's which use Bind..() methods!\n
		//! Do not forget to call FreeQuery() when you have finished.
		inline void Sql(const char *sql) {Prepare(sql);}
		//! Only for SQL queries/statements which have a result or for prepared statements.\n
		//! e.g. SELECT's or INSERT's which use Bind..() methods!\n
		//! Do not forget to call FreeQuery() when you have finished.
		inline void Sql(const std::wstring &sql) {Prepare(sql.c_str());}
		//! Only for SQL queries/statements which have a result or for prepared statements.\n
		//! e.g. SELECT's or INSERT's which use Bind..() methods!\n
		//! Do not forget to call FreeQuery() when you have finished.
		inline void Sql(const wchar_t *sql) {Prepare(sql);}

		//! If you have called Sql(), you can step throw all results.
		//! @return		'true' if there are further result rows and 'false' if there is no further result row
		bool FetchRow() const;
		//! Call FreeQuery() after Sql(), Execute() and FetchRow() to clean-up.
		void FreeQuery();

		//! Can be used for all SQLite aggregate functions.\n
		//! Here you can see all available aggregate functions: 
		//! http://sqlite.org/lang_aggfunc.html
		//! @param countSql		Complete SQL query string (UTF-16).
		double SqlAggregateFuncResult(const std::string &countSql);
		//! Can be used for all SQLite aggregate functions.\n
		//! Here you can see all available aggregate functions: 
		//! http://sqlite.org/lang_aggfunc.html
		//! @param countSql		Complete SQL query string (UTF-16).
		double SqlAggregateFuncResult(wchar_t *countSql);
		//! Can be used for all SQLite aggregate functions.\n
		//! Here you can see all available aggregate functions: 
		//! http://sqlite.org/lang_aggfunc.html
		//! @param countSql		Complete SQL query string (UTF-16).
		double SqlAggregateFuncResult(const char *countSql);

		//! Returns the name (UTF-8) assigned to a particular column in the result set of a SELECT statement.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the column name.
		const char *GetColumnName(int column) const;
		//! Returns the name (UTF-8) assigned to a particular column in the result set of a SELECT statement.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the column name.
		const char *GetColumnName(const std::string &column) const;

		//! Returns the name (UTF-16) assigned to a particular column in the result set of a SELECT statement.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the column name.
		wchar_t *GetColumnName16(int column) const;
		//! Returns the name (UTF-16) assigned to a particular column in the result set of a SELECT statement.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the column name.
		wchar_t *GetColumnName16(const std::string &column) const;

		//! Returns the datatype code for the initial data type of the result column.\n
		//! SQLITE_INTEGER		1\n
		//! SQLITE_FLOAT		2\n
		//! SQLITE_TEXT			3\n
		//! SQLITE3_TEXT		3\n
		//! SQLITE_BLOB			4\n
		//! SQLITE_NULL			5\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the column type.
		int GetColumnType(int column) const;
		//! Returns the datatype code for the initial data type of the result column.\n
		//! SQLITE_INTEGER		1\n
		//! SQLITE_FLOAT		2\n
		//! SQLITE_TEXT			3\n
		//! SQLITE3_TEXT		3\n
		//! SQLITE_BLOB			4\n
		//! SQLITE_NULL			5\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the column type.
		int GetColumnType(const std::string &column) const;

		//! Returns a character-string from a single column of the current result row of a query.\n
		//! NULL values will be returned as null pointer.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the data.
		const unsigned char *GetColumnCString(int column) const;
		//! Returns a character-string from a single column of the current result row of a query.\n
		//! NULL values will be returned as null pointer.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the data.
		const unsigned char *GetColumnCString(const std::string &column) const;

		//! Returns a std::string from a single column of the current result row of a query.\n
		//! NULL values will be represented as an empty string [std::string("")].\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the data.
		std::string GetColumnString(int column) const;
		//! Returns a std::string from a single column of the current result row of a query.\n
		//! NULL values will be represented as an empty string [std::string("")].\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the data.
		std::string GetColumnString(const std::string &column) const;

		//! Returns a UTF-16 string from a single column of the current result row of a query.\n
		//! NULL values will be returned as null pointer.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the data.
		wchar_t *GetColumnString16(int column) const;
		//! Returns a UTF-16 string from a single column of the current result row of a query.\n
		//! NULL values will be returned as null pointer.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the data.
		wchar_t *GetColumnString16(const std::string &column) const;

		//! Returns a double from a single column of the current result row of a query.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the data.
		double GetColumnDouble(int column) const;
		//! Returns a double from a single column of the current result row of a query.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the data.
		double GetColumnDouble(const std::string &column) const;

		//! Returns a int from a single column of the current result row of a query.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the data.
		int GetColumnInt(int column) const;
		//! Returns a int from a single column of the current result row of a query.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the data.
		int GetColumnInt(const std::string &column) const;

		//! Returns a bool from a single column of the current result row of a query.\n
		//! You must first call Sql()!\n
		//! Please note that GetColumnBool() will also return "false" if you use\n
		//! SqlStatement() with 'true' or 'false' as value for a bool column. Please use 1 (true)\n
		//! or 0 (false) as bool value because sqlite doesn't know the key words 'true' and 'false'.
		//! @param column		Number of the column from which we want to read the data.
		bool GetColumnBool(int column) const;
		//! Returns a bool from a single column of the current result row of a query.\n
		//! You must first call Sql()!\n
		//! Please note that GetColumnBool() will also return "false" if you use\n
		//! SqlStatement() with 'true' or 'false' as value for a bool column. Please use 1 (true)\n
		//! or 0 (false) as bool value because sqlite doesn't know the key words 'true' and 'false'.
		//! @param column		Name of the column from which we want to read the data.
		bool GetColumnBool(const std::string &column) const;

		//! Returns a int64 from a single column of the current result row of a query.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the data.
		int64 GetColumnInt64(int column) const;
		//! Returns a int64 from a single column of the current result row of a query.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the data.
		int64 GetColumnInt64(const std::string &column) const;

		//! Returns a void* from a single column of the current result row of a query.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the data.
		const void *GetColumnBlob(int column) const;
		//! Returns a void* from a single column of the current result row of a query.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the data.
		const void *GetColumnBlob(const std::string &column) const;		
		
		//! Returns the number of bytes in a column that has type BLOB or the number of bytes in a TEXT string with UTF-8 encoding.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the bytes.
		int GetColumnBytes(int column) const;
		//! Returns the same value for BLOBs but for TEXT strings returns the number of bytes in a UTF-16 encoding.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the bytes.
		int GetColumnBytes(const std::string &column) const;		
		//! Returns the same value for BLOBs but for TEXT strings returns the number of bytes in a UTF-16 encoding.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the bytes.
		int GetColumnBytes16(int column) const;
		//! Returns the same value for BLOBs but for TEXT strings returns the number of bytes in a UTF-16 encoding.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the bytes.
		int GetColumnBytes16(const std::string &column) const;		
		
		//! Returns a UTF-8 zero-terminated name of the database.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the database name.
		const char *GetColumnDatabaseName(int column) const;
		//! Returns a UTF-8 zero-terminated name of the database.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the database name.
		const char *GetColumnDatabaseName(const std::string &column) const;
		//! Returns a UTF-16 zero-terminated name of the database.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the database name.
		wchar_t *GetColumnDatabaseName16(int column) const;
		//! Returns a UTF-8 zero-terminated name of the database.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the database name.
		wchar_t *GetColumnDatabaseName16(const std::string &column) const;

		//! Returns a UTF-8 zero-terminated name of the table.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the table name.
		const char *GetColumnTableName(int column) const;
		//! Returns a UTF-8 zero-terminated name of the table.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the table name.
		const char *GetColumnTableName(const std::string &column) const;
		//! Returns a UTF-16 zero-terminated name of the table.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the table name.
		wchar_t *GetColumnTableName16(int column) const;
		//! Returns a UTF-8 zero-terminated name of the table.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the table name.
		wchar_t *GetColumnTableName16(const std::string &column) const;

		//! Returns a UTF-8 zero-terminated name of the table column.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the table column name.
		const char *GetColumnOriginName(int column) const;
		//! Returns a UTF-8 zero-terminated name of the table column.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the table column name.
		const char *GetColumnOriginName(const std::string &column) const;
		//! Returns a UTF-16 zero-terminated name of the table column.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the table column name.
		wchar_t *GetColumnOriginName16(int column) const;
		//! Returns a UTF-8 zero-terminated name of the table column.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the table column name.
		wchar_t *GetColumnOriginName16(const std::string &column) const;

		//! Returns a zero-terminated UTF-8 string containing the declared datatype of the table column.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the declared datatype of the table column.
		const char *GetColumnDeclaredDatatype(int column) const;
		//! Returns a zero-terminated UTF-8 string containing the declared datatype of the table column.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the declared datatype of the table column.
		const char *GetColumnDeclaredDatatype(const std::string &column) const;
		//! Returns a zero-terminated UTF-16 string containing the declared datatype of the table column.\n
		//! You must first call Sql()!
		//! @param column		Number of the column from which we want to read the declared datatype of the table column.
		wchar_t *GetColumnDeclaredDatatype16(int column) const;
		//! Returns a zero-terminated UTF-8 string containing the declared datatype of the table column.\n
		//! You must first call Sql()!
		//! @param column		Name of the column from which we want to read the declared datatype of the table column.
		wchar_t *GetColumnDeclaredDatatype16(const std::string &column) const;

		//! Return the number of columns in the result set.\n
		//! You must first call Sql()!
		int GetColumnCount() const;
		//! Returns the number of values in the current row of the result set.\n
		//! You must first call Sql()!
		inline int GetDataCount() const {return sqlite3_data_count(mStatement);}

		//! Overrides prior binding on the same parameter with an int value.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		//! @param value		int value which should be inserted in the indicated column
		void BindInt(int column, int value) const;
		//! Overrides prior binding on the same parameter with an bool value.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		//! @param value		bool which should be inserted in the indicated column
		void BindBool(int column, bool value) const;
		//! Overrides prior binding on the same parameter with an UTF-8 string.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		//! @param string		UTF-8 string which should be inserted in the indicated column
		void BindString(int column, const std::string &string) const;
		//! Overrides prior binding on the same parameter with an UTF-16 string.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		//! @param string		UTF-16 string which should be inserted in the indicated column
		void BindString16(int column, const wchar_t *string) const;
		//! Overrides prior binding on the same parameter with an UTF8, UTF16LE, UTF16BE, UTF16 or UTF16_ALIGNED string.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		//! @param string		UTF8, UTF16LE, UTF16BE, UTF16 or UTF16_ALIGNED string which should be inserted in the indicated column
		//! @param byteLength	Size of the string in bytes.
		//! @param encoding		Kompex::UTF8, Kompex::UTF16LE, Kompex::UTF16BE, Kompex::UTF16 (native byte order) or Kompex::UTF16_ALIGNED (sqlite3_create_collation only)
		void BindString64(int column, const char *string, uint64 byteLength, ENCODING encoding) const;
		//! Overrides prior binding on the same parameter with a double value.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		//! @param value		double value which should be inserted in the indicated column
		void BindDouble(int column, double value) const;
		//! Overrides prior binding on the same parameter with an int64 value.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		//! @param value		int64 value which should be inserted in the indicated column
		void BindInt64(int column, int64 value) const;
		//! Overrides prior binding on the same parameter with NULL.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		void BindNull(int column) const;
		//! Overrides prior binding on the same parameter with a BLOB.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column			Column, in which the data should be inserted
		//! @param data				BLOB data which should inserted in the indicated column
		//! @param numberOfBytes	The size of the second parameter (const void *data) in bytes.\n
		//!							Please pay attention, that numberOfBytes is not the number of characters!
		//!							Default: -1.\n
		//!							Negative numberOfBytes means, that the length of the string is the number of\n
		//!							bytes up to the first zero terminator.
		void BindBlob(int column, const void* data, int numberOfBytes = -1) const;
		//! Overrides prior binding on the same parameter with a BLOB.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column			Column, in which the data should be inserted
		//! @param data				BLOB data which should inserted in the indicated column
		//! @param numberOfBytes	The size of the second parameter (const void *data) in bytes.\n
		//!							In contrast to BindBlob() this method supports a 64-bit length.\n
		//!							Please pay attention, that numberOfBytes is not the number of characters!
		//!							Default: -1.\n
		//!							Negative numberOfBytes means, that the length of the string is the number of\n
		//!							bytes up to the first zero terminator.
		void BindBlob64(int column, const void* data, uint64 numberOfBytes = -1) const;
		//! Overrides prior binding on the same parameter with a blob that is filled with zeroes.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		//! @param length		length of BLOB, which is filled with zeroes
		void BindZeroBlob(int column, int length) const;
		//! Overrides prior binding on the same parameter with a blob that is filled with zeroes.\n
		//! You must call Sql() one time, before you can use Bind..() methods!
		//! @param column		Column, in which the data should be inserted
		//! @param length		Length of BLOB, which is filled with zeroes.\n
		//!						In contrast to BindZeroBlob() this method supports a 64-bit length.\n
		void BindZeroBlob64(int column, uint64 length) const;

		//! Executes a prepared statement and doesn't clean-up so that you can reuse the prepared statement.\n
		//! You must first call Sql() and Bind..() methods!\n
		//! After you executed the prepared statement while calling Execute() you must call Reset() afterwards\n
		//! so that the previous bindings will be removed. After this you can bind values with Bind() again.\n
		//! Don't forget to call FreeQuery() to clean-up if you have finsihed your work.
		void Execute() const;
		//! Executes a prepared statement and clean-up.\n
		//! You must first call Sql() and Bind..() methods! 
		void ExecuteAndFree();

		//! Returns the result as a complete table.\n
		//! Note: only for console (textoutput)\n
		//! Output: std::cout
		//! @param sql							SQL query string
		//! @param consoleOutputColumnWidth		Width of the output column within the console
		void GetTable(const std::string &sql, unsigned short consoleOutputColumnWidth = 20) const;

		//! Returns metadata about a specific column of a specific database table.
		//! Note: only console output\n
		//! Output: std::cout
		//! @param tableName		Table in which the column is found
		//! @param columnName		Column for which we want the metadata
		void GetTableColumnMetadata(const std::string &tableName, const std::string &columnName) const;

		//! Resets all SQL parameter bindings back to NULL.\n
		//! ClearBindings() does not reset the bindings on a prepared statement!
		void ClearBindings() const;

		//! Reset() is called to reset a prepared statement object back to its initial state,\n
		//! ready to be re-executed. Any SQL statement variables that had values bound to them\n
		//! using the Bind*() functions retain their values. Use ClearBindings() to reset the bindings.
		void Reset() const;

		//! Begins a transaction.
		void BeginTransaction();
		//! Commits a transaction.\n
		//! Exception output: std::cerr
		void CommitTransaction();
		//! Rollback a transaction.
		inline void RollbackTransaction()
		{
			FreeQuery();
			SqlStatement("ROLLBACK;");
		}

		//! Can be used only for transaction SQL statements.\n
		//! Can be used for transactions, if you want to use the default error handling.
		//! Please note that there is only used a reference of your sql statement.\n
		//! If your sql statement variable is invalid before you called CommitTransaction()
		//! you need to use SecureTransaction(), which creates a internal copy of your sql statement.
		//! @param sql		SQL statement
		inline void Transaction(const char *sql) {mTransactionSQL[mTransactionID++] = std::make_pair(sql, false);}
		//! Can be used only for transaction SQL statements.\n
		//! Can be used for transactions, if you want to use the default error handling.
		//! Please note that there is only used a reference of your sql statement.\n
		//! If your sql statement variable is invalid before you called CommitTransaction()
		//! you need to use SecureTransaction(), which creates a internal copy of your sql statement.
		//! @param sql		SQL statement
		inline void Transaction(const std::string &sql)	{mTransactionSQL[mTransactionID++] = std::make_pair(sql.c_str(), false);}
		//! Can be used only for transaction SQL statements.\n
		//! Can be used for transactions, if you want to use the default error handling.
		//! Please note that there is only used a reference of your sql statement.\n
		//! If your sql statement variable is invalid before you called CommitTransaction()
		//! you need to use SecureTransaction(), which creates a internal copy of your sql statement.
		//! @param sql		SQL statement
		inline void Transaction(const wchar_t *sql) {mTransactionSQL16[mTransactionID++] = std::make_pair(sql, false);}

		//! Can be used only for transaction SQL statements.\n
		//! Can be used for transactions, if you want to use the default error handling.\n
		//! The SecureTransaction() method creates a internal copy of the given sql statement string,\n
		//! so that you do not run into danger if the string will be invalid due to deletion or local scope.
		//! @param sql		SQL statement
		void SecureTransaction(const char *sql);
		//! Can be used only for transaction SQL statements.\n
		//! Can be used for transactions, if you want to use the default error handling.\n
		//! The SecureTransaction() method creates a internal copy of the given sql statement string,\n
		//! so that you do not run into danger if the string will be invalid due to deletion or local scope.
		//! @param sql		SQL statement
		void SecureTransaction(const std::string sql);
		//! Can be used only for transaction SQL statements.\n
		//! Can be used for transactions, if you want to use the default error handling.\n
		//! The SecureTransaction() method creates a internal copy of the given sql statement string,\n
		//! so that you do not run into danger if the string will be invalid due to deletion or local scope.
		//! @param sql		SQL statement
		void SecureTransaction(const wchar_t *sql);

		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		std::string GetSqlResultString(const std::string &sql, const std::string &defaultReturnValue = "");
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		std::string GetSqlResultString(const char *sql, const std::string &defaultReturnValue = "");
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		std::string GetSqlResultString(const wchar_t *sql, const std::string &defaultReturnValue = "");

		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		int GetSqlResultInt(const std::string &sql, int defaultReturnValue = -1);
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		int GetSqlResultInt(const char *sql, int defaultReturnValue = -1);
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		int GetSqlResultInt(const wchar_t *sql, int defaultReturnValue = -1);

		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		int64 GetSqlResultInt64(const std::string &sql, int64 defaultReturnValue = -1);
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		int64 GetSqlResultInt64(const char *sql, int64 defaultReturnValue = -1);
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		int64 GetSqlResultInt64(const wchar_t *sql, int64 defaultReturnValue = -1);

		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		double GetSqlResultDouble(const std::string &sql, double defaultReturnValue = -1);
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		double GetSqlResultDouble(const char *sql, double defaultReturnValue = -1);
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		double GetSqlResultDouble(const wchar_t *sql, double defaultReturnValue = -1);

		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.\n
		//! Important: You must delete the returned pointer if you don't need it anymore.\n
		//! e.g. \n
		//! const unsigned char *myValue = GetSqlResultCString("SELECT name FROM user WHERE userID = 1");\n
		//! // do domething with myValue\n
		//! delete[] myValue;
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		const unsigned char *GetSqlResultCString(const std::string &sql, const unsigned char *defaultReturnValue = 0);
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.\n
		//! Important: You must delete the returned pointer if you don't need it anymore.\n
		//! e.g. \n
		//! const unsigned char *myValue = GetSqlResultCString("SELECT name FROM user WHERE userID = 1");\n
		//! // do domething with myValue\n
		//! delete[] myValue;
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		const unsigned char *GetSqlResultCString(const char *sql, const unsigned char *defaultReturnValue = 0);
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.\n
		//! Important: You must delete the returned pointer if you don't need it anymore.\n
		//! e.g. \n
		//! const unsigned char *myValue = GetSqlResultCString("SELECT name FROM user WHERE userID = 1");\n
		//! // do domething with myValue\n
		//! delete[] myValue;
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		const unsigned char *GetSqlResultCString(const wchar_t *sql, const unsigned char *defaultReturnValue = 0); 

		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.\n
		//! Important: You must delete the returned pointer if you don't need it anymore.\n
		//! e.g. \n
		//! wchar_t *myValue = GetSqlResultString16("SELECT name FROM user WHERE userID = 1");\n
		//! // do domething with myValue\n
		//! delete[] myValue;
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		wchar_t *GetSqlResultString16(const std::string &sql, wchar_t *defaultReturnValue = 0); 
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.\n
		//! Important: You must delete the returned pointer if you don't need it anymore.\n
		//! e.g. \n
		//! wchar_t *myValue = GetSqlResultString16("SELECT name FROM user WHERE userID = 1");\n
		//! // do domething with myValue\n
		//! delete[] myValue;
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		wchar_t *GetSqlResultString16(const char *sql, wchar_t *defaultReturnValue = 0); 
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.\n
		//! Important: You must delete the returned pointer if you don't need it anymore.\n
		//! e.g. \n
		//! wchar_t *myValue = GetSqlResultString16("SELECT name FROM user WHERE userID = 1");\n
		//! // do domething with myValue\n
		//! delete[] myValue;
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		wchar_t *GetSqlResultString16(const wchar_t *sql, wchar_t *defaultReturnValue = 0); 

		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.\n
		//! Important: You must delete the returned pointer if you don't need it anymore.\n
		//! e.g. \n
		//! const void *myValue = GetSqlResultBlob("SELECT picture FROM user WHERE userID = 1");\n
		//! // do domething with myValue\n
		//! delete[] myValue;
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		const void *GetSqlResultBlob(const std::string &sql, const void *defaultReturnValue = 0); 
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.\n
		//! Important: You must delete the returned pointer if you don't need it anymore.\n
		//! e.g. \n
		//! const void *myValue = GetSqlResultBlob("SELECT picture FROM user WHERE userID = 1");\n
		//! // do domething with myValue\n
		//! delete[] myValue;
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		const void *GetSqlResultBlob(const char *sql, const void *defaultReturnValue = 0); 
		//! Executes a SQL statement and returns instantly the result value of the first column from the first row.\n
		//! Important: You must delete the returned pointer if you don't need it anymore.\n
		//! e.g. \n
		//! const void *myValue = GetSqlResultBlob("SELECT picture FROM user WHERE userID = 1");\n
		//! // do domething with myValue\n
		//! delete[] myValue;
		//! @param sql						SQL statement
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		const void *GetSqlResultBlob(const wchar_t *sql, const void *defaultReturnValue = 0);

		//! If you call this function directly after you called the Sql() function then you will get\n
		//! the total number of returned rows. If you call this function after you already requested data from the\n
		//! result then you will get the number of the remaining rows. Please note that the prepared statement will\n
		//! be reset. Therefore, you would request the data of the first result row after you called this function.
		unsigned int GetNumberOfRows();
				
		//! Formatted String Printing Function\n
		//! This function works alike the "printf()" family of functions from the standard C library.\n
		//! Furthermore, it implements some additional formatting options that are useful for constructing SQL statements.\n
		//! All of the usual printf() formatting options apply. In addition, there are "%q", "%Q", and "%z" options.\n\n
		//! <B>%q option</B>\n
		//! The %q option works like %s in that it substitutes a null-terminated string from the argument list.\n
		//! But %q also doubles every '\'' character. %q is designed for use inside a string literal.\n
		//! By doubling each '\'' character it escapes that character and allows it to be inserted into the string.\n
		//! As a general rule you should always use %q instead of %s when inserting text into a string literal.\n\n
		//! <B>%Q option</B>\n
		//! The %Q option works like %q except it also adds single quotes around the outside of the total string.\n
		//! Additionally, if the parameter in the argument list is a NULL pointer, %Q substitutes the text "NULL"\n
		//! (without single quotes).\n\n
		//! <B>%z option</B>\n
		//! The "%z" formatting option works like "%s" but with the addition that after the string has been read and\n
		//! copied into the result, sqlite3_free() is called on the input string. 
		static std::string Mprintf(const char *sql, ...);
		//! Formatted String Printing Function\n
		//! This function works alike the "printf()" family of functions from the standard C library.\n
		//! Furthermore, it implements some additional formatting options that are useful for constructing SQL statements.\n
		//! All of the usual printf() formatting options apply. In addition, there are "%q", "%Q", and "%z" options.\n\n
		//! <B>%q option</B>\n
		//! The %q option works like %s in that it substitutes a null-terminated string from the argument list.\n
		//! But %q also doubles every '\'' character. %q is designed for use inside a string literal.\n
		//! By doubling each '\'' character it escapes that character and allows it to be inserted into the string.\n
		//! As a general rule you should always use %q instead of %s when inserting text into a string literal.\n\n
		//! <B>%Q option</B>\n
		//! The %Q option works like %q except it also adds single quotes around the outside of the total string.\n
		//! Additionally, if the parameter in the argument list is a NULL pointer, %Q substitutes the text "NULL"\n
		//! (without single quotes).\n\n
		//! <B>%z option</B>\n
		//! The "%z" formatting option works like "%s" but with the addition that after the string has been read and\n
		//! copied into the result, sqlite3_free() is called on the input string. 
		static std::string Vmprintf(const char *sql, va_list args);

	protected:
		//! Compile sql query into a byte-code program.
		//! @param sqlStatement			SQL statement (UTF-8) 
		void Prepare(const char *sqlStatement);
		//! Compile sql query into a byte-code program.
		//! @param sqlStatement			SQL statement (UTF-16) 
		void Prepare(const wchar_t *sqlStatement);
		//! Must be called one or more times to evaluate the statement.
		bool Step() const;
		//! Checks if the statement pointer is valid
		void CheckStatement() const;
		//! Checks if the database pointer is valid
		void CheckDatabase() const;

		//! Returns the SQLite statement handle.
		sqlite3_stmt *GetStatementHandle() const {return mStatement;}

		//! Returns the first value of the first row. Internally used in GetSqlResultCString().
		const unsigned char *SqlResultCString(const unsigned char *defaultReturnValue);
		//! Returns the first value of the first row. Internally used in GetSqlResultString16().
		wchar_t *SqlResultString16(wchar_t *defaultReturnValue);
		//! Returns the first value of the first row. Internally used in GetSqlResultBlob().
		const void *SqlResultBlob(const void *defaultReturnValue);

		//! Checks whether the given column number is located within the available column range.
		//! @param columnNumber			column number which shall be checked
		//! @param functionName                 name of the function which shall be shown in the exception message
		void CheckColumnNumber(int columnNumber, const std::string &functionName = "") const;
		
		//! Free the allocated memory and clean the containers
		void CleanUpTransaction();

         	//! Free the allocated memory of sql statements
		//! @param isMemAllocated		Was memory allocated?
		//! @param str					SQL statement string
		template<class T>
		inline void DeleteTransactionSqlStr(bool isMemAllocated, T *str)
		{
			if(isMemAllocated)
				delete[] str;
		}

		//! Returns the first value of the first row from the given sql statement result.
		//! @param sql						SQL statement
		//! @param getColumnFunc			Function to get the SQL statement result
		//! @param defaultReturnValue		Default return value when the SQL statement has no result
		template<class S, class T>
		T GetColumnValue(S sql, T(Kompex::SQLiteStatement::*getColumnFunc)(int columnNumber)const, T defaultReturnValue);

	private:
		//! Assigns to every column number the corresponding column name.
		void AssignColumnNumberToColumnName() const;
		//! Returns the column number for a given column name.
		int GetAssignedColumnNumber(const std::string &columnName) const;

		//! SQL statement
		struct sqlite3_stmt *mStatement;
		//! Database pointer
		SQLiteDatabase *mDatabase;

		//! typedef for UTF-8 transaction statements
		typedef std::map<unsigned short /* transaction id */, std::pair<const char* /* sql */, bool /* memory allocated */> > TTransactionSQL;
		//! typedef for UTF-16 transaction statements
		typedef std::map<unsigned short /* transaction id */, std::pair<const wchar_t* /* sql */, bool /*  is memory allocated */> > TTransactionSQL16;
	
		//! Stores UTF-8 transaction statements
		TTransactionSQL mTransactionSQL;
		//! Stores UTF-16 transaction statements
		TTransactionSQL16 mTransactionSQL16;

		//! ID for transactions
		unsigned short mTransactionID;
		
		//! Container which stores the assignments for every column number and the corresponding column name (cache the results).
		mutable std::map<std::string /* column name */, int /* column number */> mColumnNumberToColumnNameAssignment;
		//! Saves whether the assignments for every column number and the corresponding column name was already done.
		mutable bool mIsColumnNumberAssignedToColumnName;

	};
};

#endif // KompexSQLiteStatement_H
